#region License

// This file is part of Grawlix.
// 
// Grawlix is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as
// published by the Free Software Foundation, either version 3 of
// the License, or (at your option) any later version.
// Grawlix is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public
// License along with Grawlix.  If not, see
// <http://www.gnu.org/licenses/>.

#endregion

using System;
using System.Diagnostics.CodeAnalysis;
using Grawlix.Application.Gui;
using Grawlix.Application.Gui.Messages;
using Grawlix.Geometry;
using Grawlix.Services;
using Grawlix.Services.Rendering;

namespace Grawlix.Application
{
	/// <summary>
	/// A governor that handles user input.
	/// </summary>

	[SuppressMessage("Microsoft.Design", "CA1001")]
	public abstract class UIGovernor : GovernorBase,
	                                   IRenderableArea,
		IDisposable
	{
		/// <summary>
		/// The <see cref="Grawlix.Application.Gui.GuiManager"/> that
		/// manages the GUI controls.
		/// </summary>
		private GuiManager _guiManager = new GuiManager();

		/// <summary>
		/// The factory used to load 
		/// </summary>
		private readonly IDynamicResourceFactory<ITextureResource>
			_textureFactory;

		/// <summary>
		/// The time since the last update.
		/// </summary>
		private TimeSpan _renderElapsed;

		/// <summary>
		/// Whether the object has already been disposed.
		/// </summary>
		private bool _disposed;

		/// <summary>
		/// Initializes a new instance of the <see cref="UIGovernor"/>
		/// class.
		/// </summary>
		/// <param name="gameKernel">The game kernel to acquire
		/// services from.</param>
		/// <exception cref="ArgumentNullException"><c>gameKernel</c>is
		/// null.</exception>
		protected UIGovernor(IGameKernel gameKernel)
			: base(gameKernel)
		{
			_textureFactory =
				GameKernel.ResolveService
					<IDynamicResourceFactory<ITextureResource>>();
		}

		/// <summary>
		/// Gets the GUI manager.
		/// </summary>
		/// <value>The GUI manager.</value>
		public GuiManager GuiManager
		{
			get { return _guiManager; }
		}

		/// <summary>
		/// Gets the texture factory.
		/// </summary>
		/// <value>The texture factory.</value>
		public IDynamicResourceFactory<ITextureResource>
			TextureFactory
		{
			get { return _textureFactory; }
		}

		/// <summary>
		/// Performs application-defined tasks associated with freeing,
		/// releasing, or resetting unmanaged resources.
		/// </summary>
		public void Dispose()
		{
			Dispose(true);
			GC.SuppressFinalize(this);
		}

		/// <summary>
		/// Releases unmanaged and - optionally - managed resources
		/// </summary>
		/// <param name="disposing"><c>true</c> to release both managed
		/// and unmanaged resources; <c>false</c> to release only
		/// unmanaged resources.</param>
		protected virtual void Dispose(bool disposing)
		{
			if (!_disposed)
			{
				if (disposing)
				{
					var manager = _guiManager;
					_guiManager = null;
					manager.Dispose();
				}
				_disposed = true;
			}
		}

		/// <summary>
		/// Responds to input messages.
		/// </summary>
		/// <param name="message">The message to respond to.</param>
		public void HandleMessage(InputMessage message)
		{
			_guiManager.SendInputMessage(message);
		}

		/// <summary>
		/// Renders to the specified device.
		/// </summary>
		/// <param name="device">The device to render to.</param>
		/// <param name="camera">The area to render within.</param>
		public virtual void Render(IRenderDevice device, Rect camera)
		{
			TimeSpan elapsed = _renderElapsed;
			_renderElapsed = TimeSpan.Zero;
			_textureFactory.Update(elapsed);
			_guiManager.Render(device, camera);
		}

		/// <summary>
		/// Updates the governor.
		/// </summary>
		/// <param name="elapsed">The elapsed time since last update.
		/// </param>
		public override void Update(TimeSpan elapsed)
		{
			_renderElapsed += elapsed;
			_guiManager.Update(elapsed);
		}
	}
}